package com.dge.common.utils

import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import androidx.lifecycle.LifecycleOwner
import com.forjrking.lubankt.Luban
import com.dge.common.common.AppConfig
import com.dge.common.extentions.isValid
import timber.log.Timber
import java.io.File

object CompressUtils {
    /**
     * @param expectSize 期望大小，单位kb
     */
    fun compress(
        context: Context,
        uris: java.util.ArrayList<Uri>,
        outPutDir: String?,
        expectSize: Long,
        onFinish: (file: List<File>) -> Unit
    ) {
        if (context !is LifecycleOwner) {
            throw IllegalArgumentException("context must be LifecycleOwner")
        }
        val fileList = ArrayList<File>()
        var onCompletionCalled = false
        var onFinishCalled = false
        Luban.with(context).load(uris)//支持 File,Uri,InputStream,String,Bitmap 和以上数据数组和集合
            .apply {
                val dir = File(outPutDir!!)
                Timber.i(
                    "outPutDir = $outPutDir, dir.exists() = ${dir.exists()}, File(outPutDir!!).isDirectory =" +
                            " ${File(outPutDir!!).isDirectory}"
                )
                if (outPutDir.isValid() && dir.isDirectory) {
                    setOutPutDir(outPutDir)
                }
            }
            .concurrent(true) //(可选)多文件压缩时是否并行,内部优化线程并行数量防止OOM
            .useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
            .format(Bitmap.CompressFormat.JPEG) //(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
            .ignoreBy(expectSize) //(可选)期望大小,大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
            .rename { FileUtil.getRandomFileName(it) }//(可选)文件重命名//重命名防重复
            // .filter { it != null }             //(可选)过滤器
            .compressObserver {
                onSuccess = {
                    Timber.i("compress onSuccess file.size = ${it.size}")
                    fileList.addAll(it)
                    if (onCompletionCalled) { //有时onCompletion调用的时候onSuccess还没执行，有时候onSuccess在onCompletion后执行
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onSuccess onFinish")
                            onFinish(fileList)
                        }
                    }
                }
                // onStart = {}
                onCompletion = {
                    Timber.i("compress onCompletion fileList.size = ${fileList.size}")
                    onCompletionCalled = true
                    if (fileList.size == uris.size) {
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onCompletion onFinish")
                            onFinish(fileList)
                        }
                    }
                }
                onError = { e, uri ->
                    Timber.i("compress onError e = ${e.message}")
                    uri?.let {
                        val file = FileUtil.getFileFromContentUri(context, it, null)
                        fileList.add(file)
                        if (onCompletionCalled && fileList.size == uris.size) {
                            if (!onFinishCalled) {
                                onFinishCalled = true
                                Timber.i("compress onError onFinish")
                                onFinish(fileList)
                            }
                        }
                    }
                }
            }.launch()
    }

    /**
     * @param expectSize 期望大小，单位kb
     */
    fun compress(context: Context, files: List<File>, expectSize: Long, onFinish: (file: List<File>) -> Unit) {
        if (context !is LifecycleOwner) {
            throw IllegalArgumentException("context must be LifecycleOwner")
        }
        val fileList = ArrayList<File>()
        var onCompletionCalled = false
        var onFinishCalled = false
        Luban.with(context).load(files)//支持 File,Uri,InputStream,String,Bitmap 和以上数据数组和集合
            // .setOutPutDir(path)  //(可选)输出目录文件夹
            .concurrent(true) //(可选)多文件压缩时是否并行,内部优化线程并行数量防止OOM
            .useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
            .format(Bitmap.CompressFormat.JPEG) //(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
            .ignoreBy(expectSize) //(可选)期望大小,大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
            .rename { FileUtil.getRandomFileName(it) }//(可选)文件重命名//重命名防重复
            //.filter { it!=null }             //(可选)过滤器
            // .quality(95)                     //(可选)质量压缩系数  0-100
            .compressObserver {
                onSuccess = {
                    Timber.i("compress onSuccess file.size = ${it.size}")
                    fileList.addAll(it)
                    if (onCompletionCalled) { //有时onCompletion调用的时候onSuccess还没执行，有时候onSuccess在onCompletion后执行
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onSuccess onFinish")
                            onFinish(fileList)
                        }
                    }
                }
                // onStart = {}
                onCompletion = {
                    Timber.i("compress onCompletion fileList.size = ${fileList.size}")
                    onCompletionCalled = true
                    if (fileList.size == files.size) {
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onCompletion onFinish")
                            onFinish(fileList)
                        }
                    }
                }
                onError = { e, file ->
                    Timber.i("compress onError e = ${e.message}")
                    file?.let { fileList.add(it) }
                    if (onCompletionCalled && fileList.size == files.size) {
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onError onFinish")
                            onFinish(fileList)
                        }
                    }
                }
            }.launch()
    }

    /**
     * 默认期望大小：期望大小(1.5M)
     */
    fun compress(context: Context, files: List<File>, onFinish: (file: List<File>) -> Unit) {
        compress(context, files, 1572864, onFinish)
    }

    /**
     * @param expectSize 期望大小，单位kb
     */
    fun compressBitmaps(
        context: Context,
        bitmaps: List<Bitmap>,
        expectSize: Long,
        onFinish: (file: List<File>) -> Unit
    ) {
        if (context !is LifecycleOwner) {
            throw IllegalArgumentException("context must be LifecycleOwner")
        }
        val fileList = ArrayList<File>()
        var onCompletionCalled = false
        var onFinishCalled = false
        Luban.with(context).load(bitmaps)//支持 File,Uri,InputStream,String,Bitmap 和以上数据数组和集合
            // .setOutPutDir(path)  //(可选)输出目录文件夹
            .concurrent(true) //(可选)多文件压缩时是否并行,内部优化线程并行数量防止OOM
            .useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
            .format(Bitmap.CompressFormat.JPEG) //(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
            .ignoreBy(expectSize) //(可选)期望大小,大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
            .rename { FileUtil.getRandomFileName(it) }//(可选)文件重命名//重命名防重复
            //.filter { it!=null }             //(可选)过滤器
            //.quality(95)                     //(可选)质量压缩系数  0-100
            .compressObserver {
                onSuccess = {
                    Timber.i("compress onSuccess file.size = ${it.size}")
                    fileList.addAll(it)
                    if (onCompletionCalled) { //有时onCompletion调用的时候onSuccess还没执行，有时候onSuccess在onCompletion后执行
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onSuccess onFinish")
                            onFinish(fileList)
                        }
                    }
                }
                // onStart = {}
                onCompletion = {
                    Timber.i("compress onCompletion fileList.size = ${fileList.size}")
                    onCompletionCalled = true
                    if (fileList.size == bitmaps.size) {
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onCompletion onFinish")
                            onFinish(fileList)
                        }
                    }
                }
                onError = { e, bitmap ->
                    Timber.i("compress onError e = ${e.message}")
                    bitmap?.let {
                        if (!bitmap.isRecycled) {
                            fileList.add(FileUtil.createBitmapFile(it))
                        }
                    }
                    if (onCompletionCalled && fileList.size == bitmaps.size) {
                        if (!onFinishCalled) {
                            onFinishCalled = true
                            Timber.i("compress onError onFinish")
                            onFinish(fileList)
                        }
                    }
                }
            }.launch()
    }

    /**
     * 默认期望大小：期望大小(1.5M)
     */
    fun compressBitmaps(context: Context, bitmaps: List<Bitmap>, onFinish: (file: List<File>) -> Unit) {
        compressBitmaps(context, bitmaps, 1572864, onFinish)
    }

    /**
     * @param expectSize 期望大小，单位kb
     */
    fun compress(context: Context, file: File, expectSize: Long, onFinish: (file: File?) -> Unit) {
        if (context !is LifecycleOwner) {
            throw IllegalArgumentException("context must be LifecycleOwner")
        }
        if (AppConfig.isDebug()) Timber.i("compress path = ${file.absolutePath}")
        Luban.with(context).load(file)//支持 File,Uri,InputStream,String,Bitmap 和以上数据数组和集合
            // .setOutPutDir(path)  //(可选)输出目录文件夹
            .concurrent(true) //(可选)多文件压缩时是否并行,内部优化线程并行数量防止OOM
            .useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
            .format(Bitmap.CompressFormat.JPEG) //(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
            .ignoreBy(expectSize) //(可选)期望大小(1.5M),大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
            .rename { FileUtil.getRandomFileName(it) }//(可选)文件重命名//重命名防重复
            //.filter { it!=null }             //(可选)过滤器
            //.quality(95)                     //(可选)质量压缩系数  0-100
            .compressObserver {
                onSuccess = {
                    if (AppConfig.isDebug()) Timber.i("compress finish file.size = ${it.length()}")
                    onFinish(it)
                }
                // onStart = {}
                // onCompletion = { }
                onError = { e, _ ->
                    if (AppConfig.isDebug()) Timber.i("compress onError e = ${e.message}")
                    onFinish(file)
                }
            }.launch()
    }

    /**
     * 同步压缩一张图片
     */
    fun compressAsync(context: Context, file: File, expectSize: Long): File {
        if (context !is LifecycleOwner) {
            throw IllegalArgumentException("context must be LifecycleOwner")
        }
        if (AppConfig.isDebug()) Timber.i("compress path = ${file.absolutePath}")
        return try {
            Luban.with(context).load(file)//支持 File,Uri,InputStream,String,Bitmap 和以上数据数组和集合
                // .setOutPutDir(path)  //(可选)输出目录文件夹
                .concurrent(true) //(可选)多文件压缩时是否并行,内部优化线程并行数量防止OOM
                .useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
                .format(Bitmap.CompressFormat.JPEG) //(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
                .ignoreBy(expectSize) //(可选)期望大小(1.5M),大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
                .rename { FileUtil.getRandomFileName(it) }//(可选)文件重命名//重命名防重复
                //.filter { it!=null }             //(可选)过滤器
                //.quality(95)                     //(可选)质量压缩系数  0-100
                .get()
        } catch (e: Exception) {
            file
        }
    }

    /**
     * 默认期望大小：期望大小(1.5M)
     */
    fun compress(context: Context, file: File, onFinish: (file: File?) -> Unit) {
        compress(context, file, 1572864, onFinish)
    }

    fun compress(
        context: Context,
        bitmap: Bitmap,
        outPutDir: String?,
        expectSize: Long,
        onFinish: (file: File?) -> Unit
    ) {
        if (context !is LifecycleOwner) {
            throw IllegalArgumentException("context must be LifecycleOwner")
        }
        Timber.i("compress width*height = ${bitmap.width}*${bitmap.height}")
        val builder = Luban.with(context).load(bitmap)//支持 File,Uri,InputStream,String,Bitmap 和以上数据数组和集合
        if (outPutDir.isValid()) {
            builder.setOutPutDir(outPutDir)  //(可选)输出目录文件夹
        }
        builder.concurrent(true) //(可选)多文件压缩时是否并行,内部优化线程并行数量防止OOM
            .useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
            .format(Bitmap.CompressFormat.JPEG) //(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
            .ignoreBy(expectSize) //(可选)期望大小(1.5M),大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
            .rename { FileUtil.getRandomFileName(it) }//(可选)文件重命名//重命名防重复
            //.filter { it!=null }             //(可选)过滤器
            //.quality(95)                     //(可选)质量压缩系数  0-100
            .compressObserver {
                onSuccess = {
                    Timber.i("compress finish file.size = ${it.length()}")
                    onFinish(it)
                }
                // onStart = {}
                // onCompletion = { }
                onError = { e, bitmap ->
                    Timber.i("compress onError e = ${e.message}")
                    if (bitmap == null || bitmap.isRecycled) {
                        onFinish(null)
                    } else {
                        onFinish(FileUtil.createBitmapFile(bitmap))
                    }
                }
            }.launch()
    }

    /**
     * @param expectSize 期望大小，单位kb
     */
    fun compress(context: Context, bitmap: Bitmap, expectSize: Long, onFinish: (file: File?) -> Unit) {
        compress(context, bitmap, null, expectSize, onFinish)
    }

    /**
     * 默认期望大小：期望大小(1.5M)
     */
    fun compress(context: Context, bitmap: Bitmap, onFinish: (file: File?) -> Unit) {
        compress(context, bitmap, 1572864, onFinish)
    }
}